#include <CL\cl.hpp>
#include <iostream>

void PrintDeviceType(cl_device_type Type)
{
	switch (Type)
	{
		case (CL_DEVICE_TYPE_GPU):
		{
			std::cout << "GPU";
			break;
		}
		case (CL_DEVICE_TYPE_CPU):
		{
			std::cout << "CPU";
			break;
		}
		case (CL_DEVICE_TYPE_ACCELERATOR):
		{
			std::cout << "Accelerator";
			break;
		}
		case (CL_DEVICE_TYPE_CUSTOM):
		{
			std::cout << "Custom";
			break;
		}
		default:
		{
			std::cout << "other (0x" << std::hex <<  Type << std::dec << ")";
			break;
		}
	}
}

void main()
{
	cl_int Result;
	cl_device_type DeviceType = CL_DEVICE_TYPE_ALL;
	std::vector<cl::Platform> Platforms;
	std::string StringValue;

	Result = cl::Platform::get(&Platforms);

	if (Result != CL_SUCCESS)
	{
		std::cerr << "Error - can't get platforms from runtime." << std::endl;
		std::cerr << "Code  - " << Result << std::endl;
	}
	else
	{
		for (std::vector<cl::Platform>::iterator CurrentPlatform = Platforms.begin(); CurrentPlatform != Platforms.end(); ++CurrentPlatform)
		{
			CurrentPlatform->getInfo(CL_PLATFORM_NAME, &StringValue);
			std::cout << "- Platfrom Name: " << StringValue << std::endl;

			CurrentPlatform->getInfo(CL_PLATFORM_VENDOR, &StringValue);
			std::cout << "- Platfrom Vendor: " << StringValue << std::endl;

			CurrentPlatform->getInfo(CL_PLATFORM_VERSION, &StringValue);
			std::cout <<"- Platfrom Version: " << StringValue << std::endl;

			CurrentPlatform->getInfo(CL_PLATFORM_PROFILE, &StringValue);
			std::cout << "- Platfrom Profile: " << StringValue << std::endl;

			CurrentPlatform->getInfo(CL_PLATFORM_EXTENSIONS, &StringValue);
			std::cout << "- Platfrom Extensions: " << StringValue << std::endl;

			if (DeviceType == CL_DEVICE_TYPE_ALL)
			{
				std::cout << "Getting all devices...";
			}
			else
			{
				std::cout << "Getting devices typed: ";
				PrintDeviceType(DeviceType);
				std::cout << "...";
			}

			std::cout << std::endl;
			
			std::vector<cl::Device> Devices;

			Result = CurrentPlatform->getDevices(DeviceType, &Devices);

			if (Result  != CL_SUCCESS)
			{
				std::cerr << "Error - can't get devices from runtime." << std::endl;
				std::cerr << "Code  - " << Result << std::endl;
			}
			else
			{
				for (std::vector<cl::Device>::iterator CurrentDevice = Devices.begin(); CurrentDevice != Devices.end(); ++CurrentDevice)
				{
					cl_bool BoolValue;
					cl_ulong UnsignedLongValue;
					cl_uint UnsignedIntValue;
					size_t SizeValue;
					cl_device_type DeviceTypeValue;
					std::vector<size_t> VectorSizeValue;
					
					std::cout << "~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~" << std::endl;			

					CurrentDevice->getInfo(CL_DEVICE_NAME, &StringValue);
					std::cout << "- Device Name: " << StringValue << std::endl;

					if (DeviceType == CL_DEVICE_TYPE_ALL)
					{
						CurrentDevice->getInfo(CL_DEVICE_TYPE, &DeviceTypeValue);
						std::cout << "- Device Type: ";
						PrintDeviceType(DeviceTypeValue);
						std::cout << std::endl;
					}

					CurrentDevice->getInfo(CL_DEVICE_VENDOR, &StringValue);
					std::cout << "- Device Vendor: " << StringValue << std::endl;

					CurrentDevice->getInfo(CL_DEVICE_VENDOR_ID, &UnsignedIntValue);
					std::cout << "- Device Vendor Id: " << UnsignedIntValue << std::endl;

					CurrentDevice->getInfo(CL_DEVICE_VERSION, &StringValue);
					std::cout << "- Device Version: " << StringValue << std::endl;

					CurrentDevice->getInfo(CL_DRIVER_VERSION, &StringValue);
					std::cout << "- Driver Version: " << StringValue << std::endl;

					CurrentDevice->getInfo(CL_DEVICE_OPENCL_C_VERSION, &StringValue);
					std::cout << "- Device OpenCL C Version: " << StringValue << std::endl;

					CurrentDevice->getInfo(CL_DEVICE_PROFILE, &StringValue);
					std::cout << "- Device Profile: " << StringValue << std::endl;

					CurrentDevice->getInfo(CL_DEVICE_MAX_COMPUTE_UNITS, &UnsignedIntValue);
					std::cout << "- Device Max Compute Units: " << UnsignedIntValue << std::endl;

					CurrentDevice->getInfo(CL_DEVICE_ENDIAN_LITTLE, &BoolValue);
					std::cout << "- Device Little Endian: " << BoolValue << std::endl;

					CurrentDevice->getInfo(CL_DEVICE_MAX_CLOCK_FREQUENCY, &UnsignedIntValue);
					std::cout << "- Device Max Clock Frequency: " << UnsignedIntValue << std::endl;

					CurrentDevice->getInfo(CL_DEVICE_ADDRESS_BITS, &UnsignedIntValue);
					std::cout << "- Device Max Address Bits: " << UnsignedIntValue << std::endl;

					CurrentDevice->getInfo(CL_DEVICE_MAX_MEM_ALLOC_SIZE, &UnsignedLongValue);
					std::cout << "- Device Max Memory Allocation Size: " << UnsignedLongValue << std::endl;

					CurrentDevice->getInfo(CL_DEVICE_MAX_WORK_ITEM_DIMENSIONS, &UnsignedIntValue);
					std::cout << "- Device Max Work Items Dimensions: " << UnsignedIntValue << std::endl;

					CurrentDevice->getInfo(CL_DEVICE_MAX_WORK_GROUP_SIZE, &SizeValue);
					std::cout << "- Device Max Work Group Size: " << SizeValue << std::endl; 

					std::cout << "- Device Max Work Item Sizes: ";
					CurrentDevice->getInfo(CL_DEVICE_MAX_WORK_ITEM_SIZES, &VectorSizeValue);
					for (std::vector<::size_t>::iterator CurrentSize = VectorSizeValue.begin(); CurrentSize != VectorSizeValue.end(); ++CurrentSize)
					{
						std::cout << *CurrentSize << ", ";
					}
					std::cout << std::endl;

					CurrentDevice->getInfo(CL_DEVICE_BUILT_IN_KERNELS, &StringValue);
					std::cout << "- Device Butit-in Kernels: " << StringValue << std::endl;

					CurrentDevice->getInfo(CL_DEVICE_EXTENSIONS, &StringValue);
					std::cout << "- Device Extensions: " << StringValue << std::endl;
				}
			}

			std::cout << std::endl;
			std::cout << "- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -" << std::endl;
			std::cout << std::endl;
		}

	}
}